//
//  GLPhotoVideoViewController.m
//  LMPhotoVideoSDK
//
//  Created by Aimar on 16/7/6.
//  Copyright © 2016年 魁钺会. All rights reserved.
//

#import "GLPhotoVideoViewController.h"
#import "GLTextureShader.h"

#define HAS_PIXELS      1
#define NO_PIXELS       0

@interface GLPhotoVideoViewController ()

@property (nonatomic, assign)GLubyte*               pixels;

@property (nonatomic, strong)NSConditionLock*       conditionLock;

@property (nonatomic, assign)double                 duration;

@property (nonatomic, assign)int                    fps;

@end


@implementation GLPhotoVideoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.pixels = (GLubyte*)malloc(self.frame.size.width * self.frame.size.height * 4);
    
    self.conditionLock = [[NSConditionLock alloc] initWithCondition:NO_PIXELS];
    
    [self convertPixelBufferToVideoFrame:self.view.bounds.size];
    
    NSArray* pics = [[NSArray alloc] initWithObjects:
        [UIImage imageNamed:@"110657-102"],
        [UIImage imageNamed:@"110794-102"],
        [UIImage imageNamed:@"110810-102"],
        [UIImage imageNamed:@"110824-102"],
        [UIImage imageNamed:@"110825-102"],
        [UIImage imageNamed:@"211103-102"],
        [UIImage imageNamed:@"211104-102"],
        [UIImage imageNamed:@"48129-102"],
        [UIImage imageNamed:@"246120-101"],
        [UIImage imageNamed:@"48127-102"],
        [UIImage imageNamed:@"334424-102"],
        [UIImage imageNamed:@"286464-101"],
        [UIImage imageNamed:@"211104-102"],
        nil
    ];

    for (UIImage* img in pics) {
        CGFloat scale = MIN(self.frame.size.width / img.size.width, self.frame.size.height / img.size.height);
        CGSize size = CGSizeMake(scale * img.size.width, scale * img.size.height);
        GLImageDrawable* drawable = [[GLImageDrawable alloc] initWithSize:size image:img];
        drawable.position = vec3(-size.width, (self.frame.size.height - size.height) / 2, 0);
        [self addDrawable:drawable];
        
        drawable.animation = [[GLTranslateAnimation alloc] initWithFrom:vec2(0, 0) to:vec2(2 * self.frame.size.width, 0)];
        drawable.animation.duration = 3000;// + rand() % 5000;
        drawable.animation.startOffset = self.duration;
        [drawable.animation startNow];
        
        self.duration += drawable.animation.duration;
    }
    
//    UIImage* img = [UIImage imageNamed:@"246120-101.jpg"];
//    GLImageDrawable* drawable = [[GLImageDrawable alloc] initWithSize:CGSizeMake(img.size.width * 0.5, img.size.height * 0.5) image:img];
//    drawable.position = vec3(7, 50, 0);
//    [self addDrawable:drawable];
//    
//    img = [UIImage imageNamed:@"286464-101.jpg"];
//    GLImageDrawable* subDrawable = [[GLImageDrawable alloc] initWithSize:CGSizeMake(img.size.width * 0.25, img.size.height * 0.25) image:img];
//    subDrawable.position = vec3(100, 100, 0);
//    [drawable addDrawable:subDrawable];
//    
//    drawable.animation = [[GLTranslateAnimation alloc] initWithFrom:vec2(0, 0) to:vec2(200, 200)];
////    _drawable.animation = [[GLRotateAnimation alloc] initWithFrom:0 to:360 pivot:vec2(_drawable.size.width / 2, _drawable.size.height / 2)];
////    drawable.animation = [[GLScaleAnimation alloc] initWithFrom:vec2(1, 1) to:vec2(0.5, 0.5) pivot:vec2(drawable.size.x / 2, drawable.size.y / 2)];
//    drawable.animation.duration = 10000;
////    drawable.animation.repeatCount = 0xffffff;
////    drawable.animation.repeatMode = GLAnimationRepeatMode_Reverse;
//    [drawable.animation startNow];
//    
//    subDrawable.animation = [[GLRotateAnimation alloc] initWithFrom:360 to:0 pivot:vec2(subDrawable.size.x / 2, subDrawable.size.y / 2)];
//    subDrawable.animation.duration = 1000;
//    subDrawable.animation.repeatCount = 0xffffff;
//    subDrawable.animation.repeatMode = GLAnimationRepeatMode_Restart;
//    [subDrawable.animation startNow];
}

- (void)draw:(GLCanvas*)canvas {
    static GLuint fbo = 0;
    static GLTexture* tex = nil;
    static GLImageDrawable* drawable = nil;
    static GLTextureShader* shader = nil;
    
    if (shader == nil) {
        shader = [[GLTextureShader alloc] initWithVertexString:normal_texture_vertex_shader fragmentString:normal_rb_swap_texture_fragment_shader];
    }
    
    if (tex == nil) {
        tex = [[GLTexture alloc] initWithUIImage:nil];
        tex.size = self.frame.size;
    }
    [tex bind];
    
    if (fbo == 0) {
        glGenFramebuffers(1, &fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.textureId, 0);
    } else {
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    }
    
    mat4 m;
    m *= mat4::Translate(-self.frame.size.width / 2, self.frame.size.height / 2, 0);
    m *= mat4::RotateX(180);
    m *= mat4::Translate(self.frame.size.width / 2, -self.frame.size.height / 2, 0);
    [canvas save];
    [canvas setCurrentMatrix:m];
    canvas.effectShader = shader;
    [super draw:canvas];
    canvas.effectShader = nil;
    [canvas restore];
    
    if (self.conditionLock != nil) {
        [self.conditionLock lockWhenCondition:NO_PIXELS];
        glReadPixels(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height, GL_RGBA, GL_UNSIGNED_BYTE, self.pixels);
        [self.conditionLock unlockWithCondition:HAS_PIXELS];
    }
    
    [((GLKView *) self.view) bindDrawable];
    glClearColor(0.2, 0.2, 0.2, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
    if (drawable == nil) {
        drawable = [[GLImageDrawable alloc] initWithSize:tex.size image:nil];
        drawable.texture = tex;
        drawable.shader = shader;
    }
    glGenerateMipmap(GL_TEXTURE_2D);
    [drawable draw:canvas];
}

- (void)convertPixelBufferToVideoFrame:(CGSize)size {
    NSString *betaCompressionDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.mp4"];
    
    NSError *error = nil;
    
    unlink([betaCompressionDirectory UTF8String]);
    
    //----initialize compression engine
    AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:betaCompressionDirectory]
                                                           fileType:AVFileTypeMPEG4
                                                              error:&error];
    NSParameterAssert(videoWriter);
    if(error)
        NSLog(@"error = %@", [error localizedDescription]);
    
    NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecH264,
                                     AVVideoWidthKey:@(size.width),
                                     AVVideoHeightKey:@(size.height)};
    AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                         outputSettings:outputSettings];
    NSDictionary *sourcePixelBufferAttributes = @{(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32RGBA)};
    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                                                                                     sourcePixelBufferAttributes:sourcePixelBufferAttributes];
    NSParameterAssert(writerInput);
    NSParameterAssert([videoWriter canAddInput:writerInput]);
    
    if ([videoWriter canAddInput:writerInput])
        NSLog(@"I can add this input");
    else
        NSLog(@"i can't add this input");
    
    [videoWriter addInput:writerInput];
    [videoWriter startWriting];
    [videoWriter startSessionAtSourceTime:kCMTimeZero];
    
    // insert demo debugging code to write the same image repeated as a movie
    dispatch_queue_t    dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
    __block int frame = 0;
    [writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{
        while (writerInput.readyForMoreMediaData) {
            [self.conditionLock lockWhenCondition:HAS_PIXELS];
            
            static const double startTime = CFAbsoluteTimeGetCurrent();
            double interval = (CFAbsoluteTimeGetCurrent() - startTime);
            double duration = (_duration / 1000); // 持续时间 单位：s
            if (interval >= duration) {
                [writerInput markAsFinished];
                [videoWriter finishWritingWithCompletionHandler:^{}];
                break;
            }
            
            NSDictionary *options = @{(__bridge NSString*)kCVPixelBufferCGImageCompatibilityKey:@(YES),
                                      (__bridge NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey:@(YES),
                                      (__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey:@(YES)};
            
            CVPixelBufferRef pxbuffer = NULL;
            CVReturn status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                                           size.width,
                                                           size.height,
                                                           kCVPixelFormatType_32BGRA,
                                                           _pixels,
                                                           4 * size.width,
                                                           NULL,
                                                           NULL,
                                                           (__bridge CFDictionaryRef)options,
                                                           &pxbuffer);
            NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
            
            static int64_t lastTime = -1;
            int32_t timeScale = 30;
            int64_t totalFrames = duration * timeScale;
            int64_t time = (interval / duration) * totalFrames;
            
            if (pxbuffer != NULL && time != lastTime) {
                lastTime = time;
                if(![adaptor appendPixelBuffer:pxbuffer withPresentationTime:CMTimeMake(time, timeScale)])
                    NSLog(@"FAIL:%lld", time);
                else
                    NSLog(@"Success:%lld", time);
                CFRelease(pxbuffer);
            }
            [self.conditionLock unlockWithCondition:NO_PIXELS];
        }
    }];
}

@end
